﻿using System.Drawing;
using System.Drawing.Drawing2D;
using System.Globalization;

namespace MathService.Functions.Plotter.GraphComponents
{
    class BasicBar : IGraphElement
    {
        private Color barColor = Color.Lime;
        private Graduation barGraduation = Graduation.Edge2;
        private Orientation barOrientation = Orientation.Vertical;
        private float barValue = 35f;
        private float borderThickness = 1f;
        private Color foreColor = Color.Black;
        private Color graphBorderColor = Color.Black;
        private float maximumValue = 100f;
        private Color outOfRangeArrowColor = Color.Salmon;
        private bool showRangeLines = true;
        private TextAlignment valueAlignment = TextAlignment.Smart;
        private string valueFormat = "";

        public float AboveRangeValue { get; set; }

        public Color BarColor { get { return barColor; } set { barColor = value; } }

        public Graduation BarGraduation { get { return barGraduation; } set { barGraduation = value; } }

        public Orientation BarOrientation { get { return barOrientation; } set { barOrientation = value; } }

        public float BarValue
        {
            get { return barValue; }
            set
            {
                if(value != barValue)
                {
                    barValue = value;
                }
            }
        }

        public float BelowRangeValue { get; set; }

        public Color BorderColor { get { return graphBorderColor; } set { graphBorderColor = value; } }

        public Rectangle ClientRectangle { get; set; }

        public Color ForeColor { get { return foreColor; } set { foreColor = value; } }

        public float MaximumValue { get { return maximumValue; } set { maximumValue = value; } }

        public float MinimumValue { get; set; }

        public Color OutOfRangeArrowColor { get { return outOfRangeArrowColor; } set { outOfRangeArrowColor = value; } }

        public bool ShowRangeLines { get { return showRangeLines; } set { showRangeLines = value; } }

        public bool ShowRangeValues { get; set; }

        public Font TextFont { get; set; }

        public TextAlignment ValueAlignment { get { return valueAlignment; } set { valueAlignment = value; } }

        public string ValueFormat { get { return valueFormat; } set { valueFormat = value; } }

        #region IGraphElement Members

        public void Draw(Graphics graphics)
        {
            RectangleF ef;
            graphics.SetClip(ClientRectangle);
            graphics.SmoothingMode = SmoothingMode.AntiAlias;
            var brush = new SolidBrush(BarColor);
            var height = 0f;
            var width = 0f;
            var num3 = MaximumValue - MinimumValue;
            if(BarOrientation == Orientation.Vertical)
            {
                height = ClientRectangle.Height*((BarValue - MinimumValue)/num3);
                width = ClientRectangle.Width;
                ef = new RectangleF(ClientRectangle.Left, ClientRectangle.Bottom - height, width, height);
            }
            else
            {
                height = ClientRectangle.Height;
                width = ClientRectangle.Width*((BarValue - MinimumValue)/num3);
                ef = new RectangleF(ClientRectangle.Left, ClientRectangle.Top, width, height);
            }
            graphics.FillRectangle(brush, ef);
            brush.Dispose();
            DrawBarValue(graphics, ef);
            DrawRangeLines(graphics, ef);
            DrawRangeValues(graphics, ef);
            var pen = new Pen(new SolidBrush(BorderColor), borderThickness);
            if(BarOrientation == Orientation.Vertical)
            {
                graphics.DrawRectangle(pen, ClientRectangle.Left, ClientRectangle.Bottom - height,
                                       width - borderThickness, height);
            }
            else
            {
                graphics.DrawRectangle(pen, ClientRectangle.Left, ClientRectangle.Bottom - height,
                                       width - borderThickness, height - borderThickness);
            }
            pen.Dispose();
            DrawGraduations(graphics, ef);
            DrawOutOfRangeArrows(graphics, ef);
        }

        #endregion

        private void DrawBarValue(Graphics graphics, RectangleF barRect)
        {
            if(ValueAlignment != TextAlignment.None)
            {
                RectangleF clientRectangle;
                Brush brush = new SolidBrush(ForeColor);
                var format = new StringFormat
                                 {
                                             Trimming = StringTrimming.Character,
                                             FormatFlags = StringFormatFlags.NoWrap
                                 };
                var text = "";
                if(ValueFormat.Length != 0)
                {
                    text = string.Format(CultureInfo.CurrentUICulture, ValueFormat, new object[] {BarValue});
                }
                else
                {
                    text = BarValue.ToString(CultureInfo.CurrentUICulture);
                }
                if(ValueAlignment == TextAlignment.AbsoluteCenter)
                {
                    format.Alignment = StringAlignment.Center;
                    format.LineAlignment = StringAlignment.Center;
                    clientRectangle = ClientRectangle;
                }
                else if(ValueAlignment == TextAlignment.BarValueCenter)
                {
                    format.Alignment = StringAlignment.Center;
                    format.LineAlignment = StringAlignment.Center;
                    clientRectangle = barRect;
                }
                else if(BarOrientation == Orientation.Vertical)
                {
                    format.Alignment = StringAlignment.Center;
                    format.LineAlignment = StringAlignment.Near;
                    if(((barRect.Top - ClientRectangle.Top) - 2f) > TextFont.Height)
                    {
                        clientRectangle = new RectangleF(barRect.Left, (barRect.Top - 2f) - TextFont.Height,
                                                         barRect.Width, barRect.Height);
                    }
                    else
                    {
                        clientRectangle = barRect;
                    }
                }
                else
                {
                    format.Alignment = StringAlignment.Far;
                    format.LineAlignment = StringAlignment.Center;
                    var ef2 = graphics.MeasureString(text, TextFont);
                    if(((barRect.Width + ef2.Width) + 2f) < ClientRectangle.Width)
                    {
                        clientRectangle = new RectangleF(barRect.Left, barRect.Top, (barRect.Width + ef2.Width) + 2f,
                                                         barRect.Height);
                    }
                    else
                    {
                        clientRectangle = barRect;
                    }
                }
                graphics.DrawString(text, TextFont, brush, clientRectangle, format);
                brush.Dispose();
            }
        }

        private void DrawGraduations(Graphics graphics, RectangleF barRect)
        {
            if(BarOrientation == Orientation.Vertical)
            {
                if(BarGraduation == Graduation.Center)
                {
                    var pen = new Pen(new SolidBrush(Color.Black), 0.25f);
                    graphics.DrawLine(pen, barRect.Left + (barRect.Width/2f), ClientRectangle.Top,
                                      barRect.Left + (barRect.Width/2f), ClientRectangle.Bottom);
                    for(var i = 0; i < ClientRectangle.Height; i += ClientRectangle.Height/5)
                    {
                        graphics.DrawLine(pen, (barRect.Left + (barRect.Width/2f)) - 5f, (ClientRectangle.Top + i),
                                          (barRect.Left + (barRect.Width/2f)) + 5f, (ClientRectangle.Top + i));
                    }
                }
                else if(BarGraduation == Graduation.Edge1)
                {
                    var pen2 = new Pen(new SolidBrush(Color.Black), 0.25f);
                    graphics.DrawLine(pen2, barRect.Left, ClientRectangle.Top, barRect.Left, ClientRectangle.Bottom);
                    for(var j = 0; j < ClientRectangle.Height; j += ClientRectangle.Height/5)
                    {
                        graphics.DrawLine(pen2, barRect.Left, (ClientRectangle.Top + j), barRect.Left + 10f,
                                          (ClientRectangle.Top + j));
                    }
                }
                else if(BarGraduation == Graduation.Edge2)
                {
                    var pen3 = new Pen(new SolidBrush(Color.Black), 0.25f);
                    graphics.DrawLine(pen3, barRect.Right - 0.25f, ClientRectangle.Top, barRect.Right - 0.25f,
                                      ClientRectangle.Bottom);
                    for(var k = 0; k < ClientRectangle.Height; k += ClientRectangle.Height/5)
                    {
                        graphics.DrawLine(pen3, barRect.Right, (ClientRectangle.Top + k), barRect.Right - 10f,
                                          (ClientRectangle.Top + k));
                    }
                }
            }
            else if(BarGraduation == Graduation.Center)
            {
                var pen4 = new Pen(new SolidBrush(Color.Black), 0.25f);
                graphics.DrawLine(pen4, ClientRectangle.Left, barRect.Top + (barRect.Height/2f), ClientRectangle.Right,
                                  barRect.Top + (barRect.Height/2f));
                for(var m = 0; m < ClientRectangle.Width; m += ClientRectangle.Width/5)
                {
                    graphics.DrawLine(pen4, (ClientRectangle.Left + m),
                                      ((ClientRectangle.Top + (ClientRectangle.Height/2)) - 5),
                                      (ClientRectangle.Left + m),
                                      ((ClientRectangle.Top + (ClientRectangle.Height/2)) + 5));
                }
            }
            else if(BarGraduation == Graduation.Edge1)
            {
                var pen5 = new Pen(new SolidBrush(Color.Black), 0.25f);
                graphics.DrawLine(pen5, ClientRectangle.Left, barRect.Top, ClientRectangle.Right, barRect.Top);
                for(var n = 0; n < ClientRectangle.Width; n += ClientRectangle.Width/5)
                {
                    graphics.DrawLine(pen5, ClientRectangle.Left + n, ClientRectangle.Top, ClientRectangle.Left + n,
                                      ClientRectangle.Top + 10);
                }
            }
            else if(BarGraduation == Graduation.Edge2)
            {
                var pen6 = new Pen(new SolidBrush(Color.Black), 0.25f);
                graphics.DrawLine(pen6, ClientRectangle.Left, barRect.Bottom, ClientRectangle.Right, barRect.Bottom);
                for(var num6 = 0; num6 < ClientRectangle.Width; num6 += ClientRectangle.Width/5)
                {
                    graphics.DrawLine(pen6, ClientRectangle.Left + num6, ClientRectangle.Bottom,
                                      ClientRectangle.Left + num6, ClientRectangle.Bottom - 10);
                }
            }
        }

        private void DrawOutOfRangeArrows(Graphics graphics, RectangleF barRect)
        {
            if(BarValue > MaximumValue)
            {
                Brush brush = new SolidBrush(OutOfRangeArrowColor);
                if(BarOrientation == Orientation.Vertical)
                {
                    var num = (ClientRectangle.Height)/10f;
                    var pen = new Pen(brush, barRect.Width/5f)
                                  {
                                              EndCap = LineCap.ArrowAnchor
                                  };
                    graphics.DrawLine(pen, (barRect.Left + (barRect.Width/2f)), (ClientRectangle.Top + (1.5f*num)),
                                      (barRect.Left + (barRect.Width/2f)), (ClientRectangle.Top + (0.5f*num)));
                }
                else
                {
                    var num2 = (ClientRectangle.Width)/10f;
                    var pen2 = new Pen(brush, barRect.Height/5f)
                                   {
                                               EndCap = LineCap.ArrowAnchor
                                   };
                    graphics.DrawLine(pen2, (ClientRectangle.Right - (1.5f*num2)),
                                      (barRect.Bottom - (barRect.Height/2f)), (ClientRectangle.Right - (0.5f*num2)),
                                      (barRect.Bottom - (barRect.Height/2f)));
                }
                brush.Dispose();
            }
            else if(BarValue < MinimumValue)
            {
                Brush brush2 = new SolidBrush(OutOfRangeArrowColor);
                if(BarOrientation == Orientation.Vertical)
                {
                    var num3 = (ClientRectangle.Height)/10f;
                    var pen3 = new Pen(brush2, barRect.Width/5f)
                                   {
                                               EndCap = LineCap.ArrowAnchor
                                   };
                    graphics.DrawLine(pen3, (barRect.Left + (barRect.Width/2f)), (ClientRectangle.Bottom - (1.5f*num3)),
                                      (barRect.Left + (barRect.Width/2f)), (ClientRectangle.Bottom - (0.5f*num3)));
                }
                else
                {
                    var num4 = (ClientRectangle.Width)/10f;
                    var pen4 = new Pen(brush2, barRect.Height/5f)
                                   {
                                               EndCap = LineCap.ArrowAnchor
                                   };
                    graphics.DrawLine(pen4, (ClientRectangle.Left + (1.5f*num4)), (barRect.Bottom - (barRect.Height/2f)),
                                      (ClientRectangle.Left + (0.5f*num4)), (barRect.Bottom - (barRect.Height/2f)));
                }
                brush2.Dispose();
            }
        }

        private void DrawRangeLines(Graphics graphics, RectangleF barRect)
        {
            if(ShowRangeLines)
            {
                var pen = new Pen(Color.Black)
                              {
                                          DashStyle = DashStyle.Dash
                              };
                if(BarOrientation == Orientation.Vertical)
                {
                    var num = ClientRectangle.Height*(AboveRangeValue/MaximumValue);
                    var num2 = ClientRectangle.Height*(BelowRangeValue/MaximumValue);
                    graphics.DrawLine(pen, barRect.Left, ClientRectangle.Height - num, barRect.Right,
                                      ClientRectangle.Height - num);
                    graphics.DrawLine(pen, barRect.Left, ClientRectangle.Height - num2, barRect.Right,
                                      ClientRectangle.Height - num2);
                }
                else
                {
                    var num3 = ClientRectangle.Width*(AboveRangeValue/MaximumValue);
                    var num4 = ClientRectangle.Width*(BelowRangeValue/MaximumValue);
                    graphics.DrawLine(pen, num3, barRect.Top, num3, barRect.Bottom);
                    graphics.DrawLine(pen, num4, barRect.Top, num4, barRect.Bottom);
                }
                pen.Dispose();
            }
        }

        private void DrawRangeValues(Graphics graphics, RectangleF barRect)
        {
            if(ShowRangeValues)
            {
                RectangleF ef;
                RectangleF ef2;
                Brush brush = new SolidBrush(ForeColor);
                var format = new StringFormat
                                 {
                                             Trimming = StringTrimming.Character,
                                             FormatFlags = StringFormatFlags.NoWrap
                                 };
                if(BarOrientation == Orientation.Vertical)
                {
                    var height = ClientRectangle.Height*(AboveRangeValue/MaximumValue);
                    var num2 = ClientRectangle.Height*(BelowRangeValue/MaximumValue);
                    var ef3 = new RectangleF(barRect.Left, ClientRectangle.Height - height, barRect.Width, height);
                    var ef4 = new RectangleF(barRect.Left, ClientRectangle.Height - num2, barRect.Width, num2);
                    format.Alignment = StringAlignment.Center;
                    format.LineAlignment = StringAlignment.Near;
                    if((ef3.Top - 2f) > TextFont.Height)
                    {
                        ef = new RectangleF(ef3.Left, (ef3.Top - 2f) - TextFont.Height, ef3.Right, ef3.Bottom);
                    }
                    else
                    {
                        ef = ef3;
                    }
                    if((ef4.Top - 2f) > TextFont.Height)
                    {
                        ef2 = new RectangleF(ef4.Left, (ef4.Top - 2f) - TextFont.Height, ef4.Right, ef4.Bottom);
                    }
                    else
                    {
                        ef2 = ef4;
                    }
                }
                else
                {
                    var width = ClientRectangle.Width*(AboveRangeValue/MaximumValue);
                    var num4 = ClientRectangle.Width*(BelowRangeValue/MaximumValue);
                    var ef5 = new RectangleF(barRect.Left, barRect.Top, width, barRect.Height);
                    var ef6 = new RectangleF(barRect.Left, barRect.Top, num4, barRect.Height);
                    format.Alignment = StringAlignment.Far;
                    format.LineAlignment = StringAlignment.Center;
                    var ef7 = graphics.MeasureString(AboveRangeValue.ToString(CultureInfo.CurrentUICulture), TextFont);
                    var ef8 = graphics.MeasureString(BelowRangeValue.ToString(CultureInfo.CurrentUICulture), TextFont);
                    if(((width + ef7.Width) + 2f) < ClientRectangle.Width)
                    {
                        ef = new RectangleF(ef5.Left, ef5.Top, (ef5.Width + ef7.Width) + 2f, ef5.Bottom);
                    }
                    else
                    {
                        ef = ef5;
                    }
                    if(((num4 + ef8.Width) + 2f) < ClientRectangle.Width)
                    {
                        ef2 = new RectangleF(ef6.Left, ef6.Top, (ef6.Width + ef8.Width) + 2f, ef6.Bottom);
                    }
                    else
                    {
                        ef2 = ef6;
                    }
                }
                graphics.DrawString(AboveRangeValue.ToString(CultureInfo.CurrentUICulture), TextFont, brush, ef, format);
                graphics.DrawString(BelowRangeValue.ToString(CultureInfo.CurrentUICulture), TextFont, brush, ef2, format);
                brush.Dispose();
            }
        }
    }
}
